extern void enable_irq(void);
extern void disable_irq(void);
 
// 任务信息结构
struct task_info {
	unsigned int sp;	// 任务栈指针
	struct task_info *next;		// 下一个任务信息结构指针
};
 
// 任务大小4096字节
#define TASK_SIZE	4096
 
// 通过当前进程的栈指针获取当前进程地址
struct task_info *current_task_info(void){
	register unsigned long sp asm ("sp");
	// sp & (~(0x00001000 - 1))
	// sp & (~(0x00000fff))
	// sp & (0xfffff000)
	// 取sp的高20位,即4k内的sp都属于一个任务
	return (struct task_info *)(sp&~(TASK_SIZE-1));
}
 
#define current	current_task_info()
 
// 任务初始化
// 当前任务成环
int task_init(void){
	current->next=current;
	return 0;
}
 
// 不允许调度即不允许中断,允许调度即允许中断
#define disable_schedule(x)	disable_irq()
#define enable_schedule(x)	enable_irq()
 
int task_stack_base = 0x30300000;		// 任务栈基址
// 通过一个任务信息复制一个任务信息,新任务的地址更高
struct task_info *copy_task_info(struct task_info *tsk){
	// 新建任务的地址由任务栈基址得到
	struct task_info *tmp=(struct task_info *)task_stack_base;
	// 更新任务栈基址
	task_stack_base+=TASK_SIZE;
	return tmp;
}
 
// 初始化栈指针
#define DO_INIT_SP(sp,fn,args,lr,cpsr,pt_base)	\
		do{\
				(sp)=(sp)-4;/*sp指向r15*/		\
				*(volatile unsigned int *)(sp)=(unsigned int)(fn);/*r15*/		\
				(sp)=(sp)-4;/*r14*/		\
				*(volatile unsigned int *)(sp)=(unsigned int)(lr);/*r14*/		\
				(sp)=(sp)-4*13;/*r12,r11,r10,r9,r8,r7,r6,r5,r4,r3,r2,r1,r0*/		\
				*(volatile unsigned int *)(sp)=(unsigned int)(args);/*r0存储args*/\
				(sp)=(sp)-4;/*cpsr*/		\
				*(volatile unsigned int *)(sp)=(unsigned int)(cpsr);\
		}while(0)
 
 
// 获取cpsr
unsigned int get_cpsr(void){
	unsigned int p;
	asm volatile(
		"mrs %0,cpsr\n"
		:"=r"(p)
		:
	);
	return p;
}
 
int do_fork(int (*f)(void *),void *args){
	struct task_info *tsk,*tmp;
	
	// 此函数完成多个功能
	// 1.获取当前任务地址但不返回
	// 2.在0x30300000处新建一个任务
	if((tsk=copy_task_info(current))==(void *)0)
		return -1;
 
	// 新建任务的栈指针初始化到顶后
	tsk->sp=((unsigned int)(tsk)+TASK_SIZE);
	
	// 新建任务的栈初始化
	// 1.设置新建任务的pc为f
	// 2.设置新建任务的r0为args
	// 3.设置新建任务的lr为0
	// 4.设置新建任务的cpsr为当前程序状态
	DO_INIT_SP(tsk->sp,f,args,0,0x1f&get_cpsr(),0);
 
	// 禁止中断,禁止调度,把新建任务插入到当前任务的下一个并成环
	disable_schedule();
	tmp = current->next;
	current->next = tsk;
	tsk->next = tmp;
	enable_schedule();
 
	return 0;
}
 
// 公共的调度函数
// 返回下个任务的地址
void *__common_schedule(void){
	return (void *)(current->next);
}